package com.piece.core.framework.util.object;

import com.alibaba.fastjson.JSONArray;
import com.piece.core.framework.constant.FrameWorkConstants;
import com.piece.core.framework.exception.ServerException;
import com.piece.core.framework.support.convert.Convert;
import com.piece.core.framework.util.basic.SpringUtil;
import com.piece.core.framework.util.collection.ArrayUtil;
import com.piece.core.framework.util.collection.CollectionUtil;
import com.piece.core.framework.util.collection.MapUtil;
import com.piece.core.framework.util.string.JsonUtil;
import com.piece.core.framework.util.string.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.cglib.core.CodeGenerationException;
import org.springframework.util.ReflectionUtils;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.sql.ResultSet;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Bean 工具类
 */
@Slf4j
public class BeanUtil {

    /**
     * Bean方法名中属性名开始的下标
     */
    private static final int BEAN_METHOD_PROP_INDEX = 3;
    /**
     * 匹配getter方法的正则表达式
     */
    private static final Pattern GET_PATTERN = Pattern.compile("get(\\p{javaUpperCase}\\w*)");
    /**
     * 匹配getter方法的正则表达式
     */
    private static final Pattern GET_BOOLEAN_PATTERN = Pattern.compile("is(\\p{javaUpperCase}\\w*)");
    /**
     * 匹配setter方法的正则表达式
     */
    private static final Pattern SET_PATTERN = Pattern.compile("set(\\p{javaUpperCase}\\w*)");

    private static Map<String, List<Method>> METHOD_CACHE = new ConcurrentHashMap();

    /**
     * 生成实例
     */
    public static <T> T newInstance(Class<T> clazz) {
        return newInstance(clazz, null, null);
    }

    /**
     * 生成实例
     */
    public static <T> T newInstance(Class<T> clazz, Class[] parameterTypes, Object[] params) {
        if (null == clazz) {
            return null;
        }
        if (ArrayUtil.isEmpty(params)) {
            try {
                return clazz.getDeclaredConstructor().newInstance();
            } catch (Exception e) {
                log.error("通过反射生成实例异常：{}", e.getMessage());
            }
        } else {
            boolean flag = false;
            Constructor constructor = null;
            try {
                constructor = getConstructor(clazz, parameterTypes);
                flag = constructor.isAccessible();
                if (!flag) {
                    constructor.setAccessible(true);
                }
                return (T) constructor.newInstance(params);
            } catch (Exception e) {
                log.error("通过反射生成实例异常：{}", e.getMessage());
            } finally {
                if (null != constructor && !flag) {
                    constructor.setAccessible(flag);
                }
            }
        }

        return null;
    }

    public static Constructor getConstructor(Class type, Class[] parameterTypes) {
        try {
            Constructor constructor = type.getDeclaredConstructor(parameterTypes);
            if (System.getSecurityManager() != null) {
                AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                    constructor.setAccessible(true);
                    return null;
                });
            } else {
                constructor.setAccessible(true);
            }

            return constructor;
        } catch (NoSuchMethodException var3) {
            throw new CodeGenerationException(var3);
        }
    }

    /**
     * Bean属性复制方法。
     *
     * @param source  源对象
     * @param target  目标对象
     */
    public static void copyBean(Object source, Object target) {
        copyBean(source, target, true, false, null);
    }

    /**
     * Bean属性复制方法。
     *
     * @param source  源对象
     * @param target  目标对象
     */
    public static void copyBean(Object source, Object target, String[] excludes) {
        copyBean(source, target, true, false, excludes);
    }

    /**
     * Bean属性复制方法。
     *
     * @param source  源对象
     * @param target  目标对象
     * @param containsParent 是否包含父类属性
     */
    public static void copyBean(Object source, Object target, boolean containsParent) {
        copyBean(source, target, true, containsParent, null);
    }

    /**
     * Bean属性复制方法。
     *
     * @param source  源对象
     * @param target  目标对象
     */
    public static void copyBeanWithOutEmpty(Object source, Object target) {
        copyBean(source, target, false, false, null);
    }

    /**
     * Bean属性复制方法。
     *
     * @param source  源对象
     * @param target  目标对象
     * @param containsParent 是否包含父类属性
     */
    public static void copyBeanWithOutEmpty(Object source, Object target, boolean containsParent) {
        copyBean(source, target, false, containsParent, null);
    }

    /**
     * Bean属性复制方法。
     *
     * @param source  源对象
     * @param target  目标对象
     * @param containsEmpty  是否拷贝非空属性
     * @param containsParent 是否包含父类属性
     */
    public static void copyBean(Object source, Object target, boolean containsEmpty, boolean containsParent, String[] excludes) {
        Map<String, Method> targetMethod = getSetterMethods(target.getClass(), containsParent);
        Map<String, Method> sourceMethod = getGetterMethods(source.getClass(), containsParent);
        try {
            targetMethod.forEach((fileName, setter) -> {
                Method getter = sourceMethod.get(fileName);
                if (null != getter && setter.getParameterTypes()[0].equals(getter.getReturnType())) {
                    String field = setter.getName().substring(BEAN_METHOD_PROP_INDEX);
                    field = field.substring(0, 1).toLowerCase() + field.substring(1);
                    try {
                        Object returnValue = getter.invoke(sourceMethod);
                        if (null != excludes && Arrays.asList(excludes).contains(field)) {
                            return;
                        }

                        if (containsEmpty || null != returnValue) {
                            setter.invoke(target, returnValue);
                        }
                    } catch (Exception e) {
                        throw new ServerException(e.getMessage());
                    }
                }
            });
        } catch (Exception e) {
            log.error("复制对象异常：{}", e.getMessage());
            throw new ServerException(e.getMessage());
        }
    }

    /**
     * 复制序列化对象
     * <p>要求对象实现了序列化接口</p>
     *
     * @param source  源对象
     * @param target  目标对象
     */
    public static void copyBeanSerializable(Object source, Object target) {
        ByteArrayOutputStream b_aos = null;
        ObjectOutputStream oos = null;
        ByteArrayInputStream b_ais = null;
        ObjectInputStream ois = null;
        try {
            b_aos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(b_aos);
            oos.writeObject(source);
            byte[] buf = b_aos.toByteArray();
            b_ais = new ByteArrayInputStream(buf);
            ois = new ObjectInputStream(b_ais);
            ois.read(buf);
            target = ois.readObject();
        } catch (Exception e) {
            log.error("复制对象异常：{}", e.getMessage());
            throw new ServerException(e.getMessage());
        } finally {
            try {
                if (null != ois) {
                    ois.close();
                }
                if (null != b_ais) {
                    b_ais.close();
                }
                if (null != oos) {
                    oos.close();
                }
                if (null != b_aos) {
                    b_aos.close();
                }
            } catch (Exception e) {
                log.error("复制对象关闭流异常：{}", e.getMessage());
            }
        }
    }

    public static Method getMethod(Class<?> beanClass, String methodName, Class<?>... paramTypes) {
        Method res = null;
        if (null != beanClass && !StringUtil.isBlank(methodName)) {
            List<Method> methods = getMethodsDirectly(beanClass, true, true);
            for (Method method: methods) {
                if (StringUtil.equals(methodName, method.getName(), true) && ClassUtil.isAllAssignableFrom(method.getParameterTypes(), paramTypes)
                        && (null == res || res.getReturnType().isAssignableFrom(method.getReturnType()))) {
                    res = method;
                }
            }
        }

        return res;
    }

    public static Method getMethodByName(Class<?> beanClass, String methodName) {
        if (null != beanClass && !StringUtil.isBlank(methodName)) {
            Method res = null;
            List<Method> methods = getMethodsDirectly(beanClass, true, true);
            for (Method method: methods) {
                if (StringUtil.equals(methodName, method.getName(), true) && (res == null || res.getReturnType().isAssignableFrom(method.getReturnType()))) {
                    res = method;
                }
            }
        }

        return null;
    }

    /**
     * 获取对象所有的setter方法。
     *
     * @param beanClass 类对象
     * @return 对象的setter方法列表
     */
    public static Map<String, Method> getSetterMethods(Class<?> beanClass) {
        return getSetterMethods(beanClass, false);
    }

    /**
     * 获取对象所有的setter方法。
     *
     * @param beanClass      类对象
     * @param containsParent 是否包含父类属性
     * @return 对象的setter方法列表
     */
    public static Map<String, Method> getSetterMethods(Class<?> beanClass, boolean containsParent) {
        // 获取所有方法
        List<Method> methods = getMethodsDirectly(beanClass, containsParent, false);

        // setter方法列表
        Map<String, Method> setterMethods = new HashMap<>();
        // 获取所有方法
        methods.stream().forEach(method -> {
            Matcher matcher = SET_PATTERN.matcher(method.getName());
            if (matcher.matches() && (method.getParameterTypes().length == 1)) {
                String fileName = StringUtil.removeStartAndLowerFirst(method.getName(), BEAN_METHOD_PROP_INDEX);
                setterMethods.put(fileName, method);
            }
        });
        // 返回setter方法列表
        return setterMethods;
    }

    /**
     * 获取对象所有的getter方法。
     *
     * @param beanClass 类对象
     * @return 对象的getter方法列表
     */
    public static Map<String, Method> getGetterMethods(Class<?> beanClass) {
        return getGetterMethods(beanClass, false);
    }

    /**
     * 获取对象所有的getter方法。
     *
     * @param beanClass      类对象
     * @param containsParent 是否包含父类属性
     * @return 对象的getter方法列表
     */
    public static Map<String, Method> getGetterMethods(Class<?> beanClass, boolean containsParent) {
        // 获取所有方法
        List<Method> methods = getMethodsDirectly(beanClass, containsParent, false);

        // getter方法列表
        Map<String, Method> getterMethods = new HashMap<>();
        // 获取所有方法
        methods.stream().forEach(method -> {
            Matcher matcher = GET_PATTERN.matcher(method.getName());
            if (matcher.matches() && (method.getParameterTypes().length == 0)) {
                String fileName = StringUtil.removeStartAndLowerFirst(method.getName(), BEAN_METHOD_PROP_INDEX);
                getterMethods.put(fileName, method);
            }
            matcher = GET_BOOLEAN_PATTERN.matcher(method.getName());
            if (matcher.matches() && (method.getParameterTypes().length == 0)) {
                String fileName = StringUtil.removeStartAndLowerFirst(method.getName(), BEAN_METHOD_PROP_INDEX - 1);
                getterMethods.put(fileName, method);
            }
        });
        // 返回getter方法列表
        return getterMethods;
    }

    public static List<Method> getMethodsDirectly(Class<?> beanClass, boolean withSupers, boolean withMethodFromObject) throws SecurityException {
        String key = getUniqueKey(beanClass) + ":" + withSupers + ":" + withMethodFromObject;
        List<Method> methods = METHOD_CACHE.get(key);

        if (CollectionUtil.isNotEmpty(methods)) {
            return methods;
        }

        methods = new ArrayList<>();
        if (beanClass.isInterface()) {
            Method[] methods_ =  withSupers ? beanClass.getMethods() : beanClass.getDeclaredMethods();
            methods.addAll(Arrays.asList(methods_));
        } else {
            for(Class searchType = beanClass; searchType != null && (withMethodFromObject || Object.class != searchType); searchType = withSupers && !searchType.isInterface() ? searchType.getSuperclass() : null) {
                Method[] methods_ = beanClass.getDeclaredMethods();
                methods.addAll(Arrays.asList(methods_));
            }
        }

        METHOD_CACHE.putIfAbsent(key, methods);
        return METHOD_CACHE.get(key);
    }

    private static List<Method> getDefaultMethodsFromInterface(Class<?> clazz) {
        List<Method> result = new ArrayList<>();
        Class[] var2 = clazz.getInterfaces();
        int var3 = var2.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            Class<?> ifc = var2[var4];
            Method[] var6 = ifc.getMethods();
            int var7 = var6.length;

            for(int var8 = 0; var8 < var7; ++var8) {
                Method m = var6[var8];
                if (!hasModifier(m, ModifierType.ABSTRACT)) {
                    result.add(m);
                }
            }
        }

        return result;
    }

    public static boolean hasModifier(Method method, ModifierType... modifierTypes) {
        if (null != method && !ArrayUtil.isEmpty(modifierTypes)) {
            return 0 != (method.getModifiers() & modifiersToInt(modifierTypes));
        } else {
            return false;
        }
    }

    public static String getUniqueKey(Class beanClass) {
        StringBuilder sb = new StringBuilder();
        sb.append(beanClass.getTypeName()).append('#');
        sb.append(beanClass.getName());
        return sb.toString();
    }

    public static String getUniqueKey(Method method) {
        StringBuilder sb = new StringBuilder();
        sb.append(method.getReturnType().getName()).append('#');
        sb.append(method.getName());
        Class<?>[] parameters = method.getParameterTypes();

        for(int i = 0; i < parameters.length; ++i) {
            if (i == 0) {
                sb.append(':');
            } else {
                sb.append(',');
            }

            sb.append(parameters[i].getName());
        }

        return sb.toString();
    }

    public static String getFieldName(String getterOrSetterName) {
        if (!getterOrSetterName.startsWith("get") && !getterOrSetterName.startsWith("set")) {
            if (getterOrSetterName.startsWith("is")) {
                return StringUtil.removeStartAndLowerFirst(getterOrSetterName, 2);
            } else {
                throw new IllegalArgumentException("Invalid Getter or Setter name: " + getterOrSetterName);
            }
        } else {
            return StringUtil.removeStartAndLowerFirst(getterOrSetterName, 3);
        }
    }

    /**
     * 检查Bean方法名中的属性名是否相等。
     *
     * @param m1 方法名1
     * @param m2 方法名2
     * @return 属性名一样返回true，否则返回false
     */
    private static boolean isMethodPropEquals(String m1, String m2) {
        return m1.substring(BEAN_METHOD_PROP_INDEX).equals(m2.substring(BEAN_METHOD_PROP_INDEX));
    }

    public static void copyProperties(Object source, Object target, String... ignoreProperties) {
        doCopyProperties(source, target, false, ignoreProperties);
    }

    public static void copyProperties(Object source, Object target, boolean ignore) {
        doCopyProperties(source, target, ignore);
    }

    private static void doCopyProperties(Object source, Object target, boolean ignore, String... ignoreProperties) {
        if (source instanceof Map) {
            if (target instanceof Map) {
                ((Map) target).putAll((Map) source);
            } else {
                mapToBean(((Map<String, Object>) source), target);
            }
        } else if (target instanceof Map) {
            beanToMap(source, (Map) target);
        } else {
            // 获取所有方法
            Arrays.stream(source.getClass().getDeclaredFields()).forEach(field -> {
                String fieldName = field.getName();
                if (!CollectionUtil.containsAny(fieldName, ignoreProperties)) {
                    Field targetField = getFieldByFieldName(target.getClass(), fieldName);
                    if (null != targetField) {
                        if (field.getType().equals(targetField.getType())) {
                            try {
                                setFieldValue(target, targetField.getName(), getFieldValue(source, field));
                            } catch (Exception e) {
                                if (!ignore) {
                                    throw new RuntimeException(e);
                                }
                            }
                        }
                    }
                }
            });
        }
    }

    /**
     * 获取obj对象fieldName的Field
     *
     * @param clazz     类
     * @param fieldName 字段属性名
     * @return 字段属性
     */
    public static Field getFieldByFieldName(Class clazz, String fieldName) {
        Field field = null;
        try {
            for (Class<?> superClass = clazz; null == field; superClass = superClass.getSuperclass()) {
                for (Field declaredField : superClass.getDeclaredFields()) {
                    if (declaredField.getName().toUpperCase().equals(fieldName.toUpperCase())) {
                        field = declaredField;
                        return field;
                    }
                }
            }
        } catch (Exception e) {
            return null;
        }

        return field;
    }

    /**
     * 获取obj对象fieldName的属性值
     *
     * @param bean      对象
     * @param fieldName 字段属性名
     * @return 字段属性值
     */
    public static Object getFieldValue(Object bean, String fieldName) {
        if (null != bean && null != fieldName) {
            if (bean instanceof Map) {
                return ((Map)bean).get(fieldName);
            } else if (bean instanceof Collection) {
                try {
                    return CollectionUtil.get((Collection)bean, Integer.parseInt(fieldName));
                } catch (NumberFormatException var3) {
                    return CollectionUtil.convertList((Collection)bean, (beanEle) -> getFieldValue(beanEle, fieldName), false);
                }
            } else if (ArrayUtil.isArray(bean)) {
                try {
                    return ArrayUtil.get(bean, Integer.parseInt(fieldName));
                } catch (NumberFormatException var4) {
                    return ArrayUtil.convertArray(bean, Object.class, (beanEle) -> {
                        return getFieldValue(beanEle, fieldName);
                    });
                }
            } else {
                Field field = getFieldByFieldName(bean.getClass(), fieldName);
                return getFieldValue(bean, field);
            }
        } else {
            return null;
        }
    }

    public static Object getFieldValue(Object bean, Field field) {
        Object value = null;
        try {
            if (null != field) {
                if (!field.isAccessible()) {
                    field.setAccessible(true);
                }
                value = field.get(bean);
            }
        } catch (IllegalAccessException e) {
            log.error("获取对象属性值异常：{}", e.getMessage());
        }
        return value;
    }

    /**
     * 设置obj对象fieldName的属性值
     *
     * @param bean      对象
     * @param fieldName 字段属性名
     * @param value     字段属性值
     */
    public static void setFieldValue(Object bean, String fieldName, Object value) throws Exception {
        if (bean instanceof Map) {
            ((Map)bean).put(fieldName, value);
        } else if (bean instanceof List) {
            CollectionUtil.setOrAppend((List)bean, Convert.toInt(fieldName), value);
        } else if (ArrayUtil.isArray(bean)) {
            ArrayUtil.setOrAppend(bean, Convert.toInt(fieldName), value);
        } else {
            try {
                Field field = getFieldByFieldName(bean.getClass(), fieldName);
                if (field.isAccessible()) {
                    setFieldValue(bean, field, value);
                } else {
                    field.setAccessible(true);
                    setFieldValue(bean, field, value);
                    field.setAccessible(false);
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 设置obj对象fieldName的属性值
     *
     * @param bean
     * @param field
     * @param value
     */
    public static void setFieldValue(Object bean, Field field, Object value) throws Exception {
        // 取得类型,并根据对象类型设置值.
        Class<?> fieldType = field.getType();
        field.setAccessible(true);

        if (String.class == fieldType) {
            field.set(bean, Convert.toStr(value));
        } else if ((Integer.TYPE == fieldType) || (Integer.class == fieldType)) {
            field.set(bean, Convert.toInt(value));
        } else if ((Long.TYPE == fieldType) || (Long.class == fieldType)) {
            field.set(bean, Convert.toLong(value));
        } else if ((Float.TYPE == fieldType) || (Float.class == fieldType)) {
            field.set(bean, Convert.toFloat(value));
        } else if ((Short.TYPE == fieldType) || (Short.class == fieldType)) {
            field.set(bean, Convert.toShort(value));
        } else if ((Double.TYPE == fieldType) || (Double.class == fieldType)) {
            field.set(bean, Convert.toDouble(value));
        } else if (Character.TYPE == fieldType) {
            field.set(bean, Convert.toChar(value));
        } else if (Number.class == fieldType) {
            field.set(bean, Convert.toBigDecimal(value));
        } else if (BigDecimal.class.isAssignableFrom(fieldType) || BigDecimal.class == fieldType) {
            field.set(bean, Convert.toBigDecimal(value));
        } else if (Date.class == fieldType) {
            field.set(bean, Convert.toDate(value));
        } else if (Boolean.class == fieldType) {
            field.set(bean, Convert.toBool(value));
        } else {
            field.set(bean, value);
        }
    }

    public static void updateFieldValue(Object bean, Field field, Object value) throws Exception {
        // 取得类型,并根据对象类型设置值.
        Class<?> fieldType = field.getType();
        Object source = getFieldValue(bean, field);
        field.setAccessible(true);

        if (String.class == fieldType) {
            if (ObjectUtil.isNotEmpty(source) && ObjectUtil.isNotEmpty(value)) {
                field.set(bean, Convert.toStr(source, "") + FrameWorkConstants.SPLIT_PARAM + Convert.toStr(value, ""));
                return;
            }
            field.set(bean, Convert.toStr(value));
        } else if ((Integer.TYPE == fieldType) || (Integer.class == fieldType)) {
            if (ObjectUtil.isNotEmpty(source) && ObjectUtil.isNotEmpty(value)) {
                field.set(bean, Convert.toInt(source, 0) + Convert.toInt(value, 0));
                return;
            }
            field.set(bean, Convert.toInt(value));
        } else if ((Long.TYPE == fieldType) || (Long.class == fieldType)) {
            if (ObjectUtil.isNotEmpty(source) && ObjectUtil.isNotEmpty(value)) {
                field.set(bean, Convert.toLong(source, 0L) + Convert.toLong(value, 0L));
                return;
            }
            field.set(bean, Convert.toLong(value));
        } else if ((Float.TYPE == fieldType) || (Float.class == fieldType)) {
            if (ObjectUtil.isNotEmpty(source) && ObjectUtil.isNotEmpty(value)) {
                field.set(bean, Convert.toFloat(source, 0F) + Convert.toFloat(value, 0F));
                return;
            }
            field.set(bean, Convert.toFloat(value));
        } else if ((Short.TYPE == fieldType) || (Short.class == fieldType)) {
            if (ObjectUtil.isNotEmpty(source) && ObjectUtil.isNotEmpty(value)) {
                field.set(bean, Convert.toShort(source, (short) 0) + Convert.toShort(value, (short) 0));
                return;
            }
            field.set(bean, Convert.toShort(value));
        } else if ((Double.TYPE == fieldType) || (Double.class == fieldType)) {
            if (ObjectUtil.isNotEmpty(source) && ObjectUtil.isNotEmpty(value)) {
                field.set(bean, Convert.toDouble(source, (double) 0) + Convert.toDouble(value, (double) 0));
                return;
            }
            field.set(bean, Convert.toDouble(value));
        } else if (Character.TYPE == fieldType) {
            field.set(bean, Convert.toChar(value));
        } else if (Number.class == fieldType) {
            if (ObjectUtil.isNotEmpty(source) && ObjectUtil.isNotEmpty(value)) {
                field.set(bean, Convert.toBigDecimal(source).add(Convert.toBigDecimal(value)));
                return;
            }
            field.set(bean, Convert.toBigDecimal(value));
        } else if (BigDecimal.class.isAssignableFrom(fieldType) || BigDecimal.class == fieldType) {
            if (ObjectUtil.isNotEmpty(source) && ObjectUtil.isNotEmpty(value)) {
                field.set(bean, Convert.toBigDecimal(source).add(Convert.toBigDecimal(value)));
                return;
            }
            field.set(bean, Convert.toBigDecimal(value));
        } else if (Date.class == fieldType) {
            field.set(bean, Convert.toDate(value));
        } else if (Boolean.class == fieldType) {
            field.set(bean, Convert.toBool(value));
        } else {
            field.set(bean, value);
        }
    }

    /**
     * 将对象转换为map
     *
     * @param bean    对象
     * @param target  目标对象
     */
    public static Map beanToMap(Object bean, Map target) {
        return beanToMap(bean, target, true);
    }

    /**
     * 将对象转换为map
     *
     * @param bean          源对象
     * @param target        目标对象
     * @param containsEmpty 是否复制空值属性
     */
    public static Map beanToMap(Object bean, Map target, boolean containsEmpty) {
        if (null != bean) {
            BeanMap beanMap = BeanMap.create(bean);
            for (Object key : beanMap.keySet()) {
                if (null != beanMap.get(key) || containsEmpty) {
                    target.put(key.toString(), beanMap.get(key));
                }
            }
        }

        return target;
    }

    /**
     * 将map转换为javabean对象
     *
     * @param map  map对象
     * @param bean 实体类
     * @return bean
     */
    public static <T> T mapToBean(Map<String, Object> map, T bean) {
        Map<String, Object> fieldMap = getAllFieldsName(bean);
        fieldMap.forEach((name, value) -> {
            Object object = map.get(name);
            try {
                setFieldValue(bean, name, object);
            } catch (Exception e) {
            }
        });
        return bean;
    }

    /**
     * 将sql查询结果转换为javabean对象
     *
     * @param map  sql查询结果集
     * @param bean 实体类
     * @return bean
     */
    public static <T> T resultMapToBean(Map<String, Object> map, T bean) {
        Map<String, Field> fieldMap = getAllDbFields(bean.getClass());
        if (null != fieldMap && null != map) {
            try {
                fieldMap.forEach((name, field) -> {
                    try {
                        Object value = map.get(name);
                        if (null == value) {
                            value = map.get(field.getName());
                        }
                        if (null == value) {
                            value = map.get(field.getName().toUpperCase());
                        }
                        field.setAccessible(true);
                        setFieldValue(bean, field, value);
                    } catch (Exception e) {
                        log.error("sql查询结果转换对象异常：{}", e.getMessage());
                    }
                });
            } catch (Exception e) {
                log.error("sql查询结果转换对象异常：{}", e.getMessage());
            }
        }
        return bean;
    }

    /**
     * 将List<Map<String, Object>>转换为实体类对象
     *
     * @param mapList List对象
     * @param clazz   实体类对象
     */
    public static <T> List<T> resultMapToBean(List<Map<String, Object>> mapList, Class<T> clazz) throws Exception {
        List<T> list = new ArrayList<T>();
        if (mapList != null && mapList.size() > 0) {
            Map<String, Object> map;
            T bean = null;
            for (int i = 0, size = mapList.size(); i < size; i++) {
                bean = clazz.newInstance();
                resultMapToBean(mapList.get(i), bean);
                list.add(bean);
            }
        }
        return list;
    }

    /**
     * 将resultSet转换为javabean对象
     *
     * @param rs   ResultSet结果集
     * @param bean 实体类
     * @return bean
     */
    public static <T> T resultSetToBean(ResultSet rs, T bean) {
        Map<String, Field> fieldMap = getAllDbFields(bean.getClass());
        if (null != fieldMap && null != rs) {
            fieldMap.forEach((name, field) -> {
                try {
                    Column column = field.getAnnotation(Column.class);
                    String columnName = field.getName();
                    if (null != column) {
                        columnName = column.name();
                    }
                    field.setAccessible(true);
                    Object value = rs.getObject(columnName);
                    value = null == value ? rs.getObject(columnName.toUpperCase()) : value;
                    setFieldValue(bean, field, value);
                } catch (Exception e) {
                    log.error("resultSet转换对象异常：{}", e.getMessage());
                }
            });
        }
        return bean;
    }

    /**
     * 将List转换为List<Map<String,Object>>
     */
    public static <T> List<Map<String, Object>> beanToMap(List<T> obj_list) {
        List<Map<String, Object>> list = new ArrayList<>();
        if (null != obj_list && obj_list.size() > 0) {
            T bean;
            for (int i = 0, size = obj_list.size(); i < size; i++) {
                bean = obj_list.get(i);
                Map<String, Object> map = new HashMap<>();
                beanToMap(bean, map);
                list.add(map);
            }
        }
        return list;
    }

    /**
     * 将List<Map<String,Object>>转换为List
     */
    public static <T> List<T> mapToBean(List<Map<String, Object>> list_map, Class<T> clazz) {
        List<T> list = new ArrayList<T>();
        if (null != list_map && list_map.size() > 0) {
            list_map.stream().forEach(map -> {
                try {
                    T bean = clazz.newInstance();
                    mapToBean(map, bean);
                    list.add(bean);
                } catch (Exception e) {
                    throw new ServerException(e.getMessage());
                }
            });
        }
        return list;
    }

    /**
     * 获取对象属性变更内容
     *
     * @param source  原对象
     * @param target  修改后的对象
     * @return Map中key值为变化的属性名称，value为属性值[原值,新值], 返回null说明对象属性没有变化
     */
    public static <T1, T2> Map<String, Object[]> compare(T1 source, T2 target) {
        if (null == source || null == target) {
            return null;
        }
        Map<String, Object[]> result = new HashMap<>();
        Field[] target_fs = target.getClass().getDeclaredFields();
        Arrays.stream(target_fs).forEach(field -> {
            try {
                String fName = field.getName();
                // 比较两个对象之间的值
                field.setAccessible(true);
                // 变更前的值
                Object sv;
                // 变更后的值
                Object dv = field.get(target);
                try {
                    sv = getFieldValue(source, fName);
                    if (isDiff(sv, dv)) {
                        result.put(fName, new Object[]{sv, dv});
                    }
                } catch (Exception e) {
                }
            } catch (IllegalAccessException e) {
                log.error("获取对象变更内容异常：{}", e.getMessage());
            }
        });
        return result;
    }

    /**
     * 判断两个对象值是否相同
     *
     * @param source  原值
     * @param target  比对值
     * @return true：不相同 false：相同
     */
    public static boolean isDiff(Object source, Object target) {
        if (null == source && null == target) {
            return false;
        }

        if (null == source || null == target) {
            return true;
        }

        if (ClassUtil.isWrapClass(source.getClass())) {
            return !source.equals(target);
        } else if (ClassUtil.isJsonArray(source)) {
            JSONArray sourceArray = (JSONArray) JSONArray.toJSON(source);
            JSONArray targetArray = (JSONArray) JSONArray.toJSON(target);
            return sourceArray.equals(targetArray);
        }

        Field[] target_fs = target.getClass().getDeclaredFields();
        for (Field df : target_fs) {
            String fName = df.getName();
            // 比较两个对象之间的值
            df.setAccessible(true);
            // 变更前的值
            Object sv;
            try {
                // 变更后的值
                Object dv = df.get(target);
                sv = getFieldValue(source, fName);
                if (isDiff(sv, dv)) {
                    return false;
                }
            } catch (Exception e) {
                continue;
            }
        }
        return true;
    }

    /**
     * 记录对象变更信息
     *
     * @param source 原值
     * @param target 比对值
     */
    public static List<Map> diffRecord(Object source, Object target) {
        return diffRecord(source, target, "", null);
    }

    /**
     * 记录对象变更信息
     *
     * @param source 原值
     * @param target 比对值
     */
    public static List<Map> diffRecord(Object source, Object target, String defaultName, List<Class<javax.persistence.Transient>> transients) {
        List<Map> records = new ArrayList<>();
        Object source_ = source;
        Object target_ = target;

        if (null == source) {
            source_ = BeanUtil.newInstance(target.getClass());
        }
        if (null == target) {
            target_ = BeanUtil.newInstance(source.getClass());
        }

        if (ClassUtil.isWrapClass(source_.getClass()) || ClassUtil.isJsonArray(source_)) {
            if (isDiff(source_, target_)) {
                records.add(MapUtil.builder()
                        .put("filedName", defaultName)
                        .put("oldValue", JsonUtil.toJson(source_))
                        .put("newValue", JsonUtil.toJson(target_))
                        .build());
            }
            return records;
        }

        Field[] source_fs = source_.getClass().getDeclaredFields();
        for (Field df : source_fs) {
            String fName = df.getName();
            if (null != transients) {
                for (Class<javax.persistence.Transient> enumType : transients) {
                    if (null != df.getAnnotation(enumType)) {
                        continue;
                    }
                }
            }

            // 比较两个对象之间的值
            df.setAccessible(true);
            // 变更前的值
            Object sv;
            try {
                // 变更后的值
                Object dv = df.get(target_);
                sv = getFieldValue(source_, fName);
                if (isDiff(sv, dv)) {
                    records.add(MapUtil.builder()
                            .put("filedName", fName)
                            .put("oldValue", JsonUtil.toJson(Convert.toStr(sv, "")))
                            .put("newValue", JsonUtil.toJson(Convert.toStr(dv, "")))
                            .build());
                }
            } catch (Exception e) {
                continue;
            }
        }

        return records;
    }

    /**
     * 获取数据表名称
     *
     * @param clazz 对象类型
     * @return 数据表名称
     */
    public static <T> String getTableName(Class<T> clazz) {
        return getTableName(clazz, false);
    }

    /**
     * 获取数据表名称
     *
     * @param clazz 对象类型
     * @return 数据表名称
     */
    public static <T> String getTableName(Class<T> clazz, boolean isClassName) {
        try {
            if (isClassName) {
                return clazz.getSimpleName();
            }
            Entity entity = clazz.getAnnotation(Entity.class);
            if (null != entity && StringUtil.isNotEmpty(entity.name())) {
                return entity.name();
            }
            Table table = clazz.getAnnotation(Table.class);
            if (null != table && StringUtil.isNotEmpty(table.name())) {
                return table.name();
            }
            return clazz.getSimpleName();
        } catch (Exception e) {
            log.error("获取主键属性名称异常：{}", e.getMessage());
        }
        return null;
    }

    public static String getColumnName(Class clazz, String fieldName) {
        return getColumnName(clazz, fieldName, false);
    }

    public static String getColumnName(Class clazz, String fieldName, boolean isFieldName) {
        try {
            Field field = clazz.getDeclaredField(fieldName);
            if (null != field) {
                Column annotation = field.getAnnotation(Column.class);
                if (!isFieldName && null != annotation) {
                    return null != annotation.name() ? annotation.name() : fieldName;
                }
                return fieldName;
            }
        } catch (Exception e) {
            if (null != clazz.getSuperclass()) {
                return getColumnName(clazz.getSuperclass(), fieldName, isFieldName);
            }
            log.error("获取数据库属性名称异常：{}", e.getMessage());
        }
        return fieldName;
    }

    /**
     * 获取主键属性名称
     *
     * @param obj 对象
     * @return 主键属性名称
     */
    public static String getKeyName(Object obj) {
        Object[] result = getKeyProperties(obj);
        if (null != result) {
            return (String) result[0];
        }
        return null;
    }

    /**
     * 获取主键属性名称
     */
    public static String getKeyName(Class clazz) {
        return getKeyName(clazz, false);
    }

    /**
     * 获取主键属性名称
     */
    public static String getKeyName(Class clazz, boolean isFieldName) {
        return getKeyName(clazz, null, isFieldName);
    }

    public static String getKeyName(Class clazz, Class<java.lang.annotation.Annotation> keyClass, boolean isFieldName) {
        try {
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                Object id = field.getAnnotation(Id.class);
                if (null != keyClass) {
                    id = field.getAnnotation(keyClass);
                }

                if (null != id) {
                    Column column = field.getAnnotation(Column.class);
                    if (!isFieldName && null != column && StringUtil.isNotEmpty(column.name())) {
                        return column.name();
                    }
                    return field.getName();
                }
            }
        } catch (Exception e) {
            log.error("获取主键属性名称异常：{}", e.getMessage());
        }
        return null;
    }

    /**
     * 获取主键值
     *
     * @param obj 对象
     * @return 主键值
     */
    public static Object getKeyValue(Object obj) {
        Object[] result = getKeyProperties(obj);
        if (null != result) {
            return result[1];
        }
        Field[] fields = obj.getClass().getDeclaredFields();
        return getFieldValue(obj, fields[0]);
    }

    /**
     * 获取主键属性名称和属性值
     *
     * @param obj 对象
     * @return Object[属性名，属性值]
     */
    public static Object[] getKeyProperties(Object obj) {
        return getKeyProperties(obj, false);
    }

    /**
     * 获取主键属性名称和属性值
     *
     * @param obj         对象
     * @param isFieldName 是否类属性：true-类属性名 false-数据库字段名
     * @return Object[属性名，属性值]
     */
    public static Object[] getKeyProperties(Object obj, boolean isFieldName) {
        return getKeyProperties(obj, null, isFieldName);
    }

    public static Object[] getKeyProperties(Object obj, Class<java.lang.annotation.Annotation> keyClass, boolean isFieldName) {
        Object[] result = new Object[2];
        try {
            Field[] fields = obj.getClass().getDeclaredFields();
            for (Field field : fields) {
                Object id = field.getAnnotation(Id.class);
                if (null != keyClass) {
                    id = field.getAnnotation(keyClass);
                }

                if (null != id) {
                    field.setAccessible(true);
                    result[0] = getKeyName(obj.getClass(), isFieldName);
                    result[1] = field.get(obj);
                    return result;
                }
            }
        } catch (Exception e) {
            log.error("获取主键属性异常：{}", e.getMessage());
        }
        return null;
    }

    /**
     * 获取主键类型
     */
    public static Class getKeyType(Class clazz) {
        return getKeyType(clazz, null);
    }

    public static Class getKeyType(Class clazz, Class<java.lang.annotation.Annotation> keyClass) {
        try {
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                Object id = field.getAnnotation(Id.class);
                if (null != keyClass) {
                    id = field.getAnnotation(keyClass);
                }

                if (null != id) {
                    return field.getType();
                }
            }
        } catch (Exception e) {
            log.error("获取主键类型异常：{}", e.getMessage());
        }
        return null;
    }

    /**
     * 判断对象是否包含属性
     */
    public static boolean hasField(Class clazz, String fieldName) {
        try {
            Field field = clazz.getDeclaredField(fieldName);
            if (null != field) {
                return true;
            }
        } catch (Exception e) {
        }
        return false;
    }

    /**
     * 获取类中所有column属性名与属性值
     *
     * @param obj 对象
     * @return Map<属性名, 属性值>
     */
    public static Map<String, Object> getAllFieldsName(Object obj) {
        return getAllFieldsName(obj, true);
    }

    /**
     * 获取类中所有数据库对应字段名和Field
     *
     * @param clazz 对象
     */
    public static Map<String, Field> getAllDbFields(Class clazz) {
        return getAllDbFields(clazz, null);
    }

    public static Map<String, Field> getAllDbFields(Class clazz, Class<java.lang.annotation.Annotation> keyClass) {
        Map<String, Field> result = new HashMap<>();
        try {
            Field[] fields = clazz.getDeclaredFields();
            Arrays.stream(fields).forEach(field -> {
                boolean add = false;
                Object id = field.getAnnotation(Id.class);
                Column column = field.getAnnotation(Column.class);
                if (null != keyClass) {
                    id = field.getAnnotation(keyClass);
                }

                String dbName = null;
                if (null != column) {
                    dbName = column.name();
                    add = true;
                } else if (null != id) {
                    add = true;
                }
                if (add) {
                    result.put(null != dbName ? dbName : field.getName(), field);
                }
            });
        } catch (Exception e) {
            log.error("获取对象对应数据库字段名异常：{}", e.getMessage());
        }
        return result;
    }

    /**
     * 获取类中所有column属性名与属性值
     *
     * @param obj           对象
     * @param containsEmpty 是否包含空值属性
     */
    public static Map<String, Object> getAllFieldsName(Object obj, boolean containsEmpty) {
        return getAllFieldsName(obj, null, containsEmpty);
    }

    public static Map<String, Object> getAllFieldsName(Object obj, Class<java.lang.annotation.Annotation> keyClass, boolean containsEmpty) {
        Map<String, Object> result = new HashMap<>();
        Field[] fields = obj.getClass().getDeclaredFields();
        Arrays.stream(fields).forEach(field -> {
            Object id = field.getAnnotation(Id.class);
            Column column = field.getAnnotation(Column.class);

            if (null != keyClass) {
                id = field.getAnnotation(keyClass);
            }

            try {
                field.setAccessible(true);
                if (containsEmpty) {
                    result.put(field.getName(), null);
                } else {
                    Object val = field.get(obj);
                    if (null != column || null != id) {
                        if (val != null || containsEmpty) {
                            result.put(field.getName(), val);
                        }
                    }
                }
            } catch (IllegalAccessException e) {
                log.error("获取对象属性异常：{}", e.getMessage());
            }
        });
        return result;
    }

    /**
     * 将sql结果集转换为实体类对象
     *
     * @param mapList List对象
     * @param clazz   实体类对象
     */
    public static <T> List<T> sqlMapToBean(List<Map> mapList, Class<T> clazz) {
        List<T> list = new ArrayList<>();
        if (ObjectUtil.isNotEmpty(mapList)) {
            mapList.stream().forEach(map -> {
                try {
                    T bean = (T) sqlMapToBean(map, clazz);
                    if (null != bean) {
                        list.add(bean);
                    }
                } catch (Exception e) {
                    throw new ServerException(e.getMessage());
                }
            });
        }
        return list;
    }

    /**
     * 将sql查询结果转换为javabean对象
     *
     * @param map   sql查询结果集
     * @param clazz 实体类对象
     * @return bean
     */
    public static <T> T sqlMapToBean(Map<String, Object> map, Class<T> clazz) throws Exception {
        T bean = clazz.newInstance();

        if (ObjectUtil.isNotEmpty(map)) {
            map.forEach((name, value) -> {
                try {
                    if (name.indexOf(".") > 0) {
                        String fieldName = name.substring(0, name.indexOf("."));
                        fieldName = StringUtil.convertToCamelCase(fieldName);
                        String subFieldName = name.substring(name.indexOf(".") + 1);
                        subFieldName = StringUtil.convertToCamelCase(subFieldName);
                        Field field = getFieldByFieldName(clazz, fieldName);
                        if (null != field) {
                            field.setAccessible(true);
                            Object property = getFieldValue(bean, fieldName);
                            if (null == property) {
                                property = field.getType().newInstance();
                            }
                            // 更新属性值
                            Field subField = getFieldByFieldName(property.getClass(), subFieldName);
                            if (null != subField) {
                                subField.setAccessible(true);
                                // 更新子实体类值
                                setFieldValue(property, subField, value);
                                // 更新父实体类值
                                setFieldValue(bean, field, property);
                            }
                        }
                    } else {
                        String fieldName = StringUtil.convertToCamelCase(name);
                        Field field = getFieldByFieldName(bean.getClass(), fieldName);
                        if (null != field) {
                            field.setAccessible(true);
                            setFieldValue(bean, field, value);
                        }
                    }
                } catch (Exception e) {
                    log.error("sql查询结果转换对象异常：{}", e.getMessage());
                }
            });
        }

        return bean;
    }

    public enum ModifierType {
        PUBLIC(1),
        PRIVATE(2),
        PROTECTED(4),
        STATIC(8),
        FINAL(16),
        SYNCHRONIZED(32),
        VOLATILE(64),
        TRANSIENT(128),
        NATIVE(256),
        ABSTRACT(1024),
        STRICT(2048);

        private final int value;

        ModifierType(int modifier) {
            this.value = modifier;
        }

        public int getValue() {
            return this.value;
        }
    }

    private static int modifiersToInt(ModifierType... modifierTypes) {
        int modifier = modifierTypes[0].getValue();

        for(int i = 1; i < modifierTypes.length; ++i) {
            modifier |= modifierTypes[i].getValue();
        }

        return modifier;
    }

    public static <T> Object exec(String className, String methodName) throws RuntimeException {
        return exec(className, methodName, null);
    }

    public static <T> Object exec(String className, String methodName, Object... args) throws RuntimeException {
        Object bean = SpringUtil.getBean(className);
        return exec(bean, methodName, args);
    }

    public static <T> Object exec(Object bean, String methodName, Object... args) throws RuntimeException {
        try {
            if (null == args) {
                args = new Object[0];
            }

            Class[] actualArgs = new Class[args.length];
            if (actualArgs.length > 0) {
                for (int i = 0; i < args.length; i++) {
                    if (null != args[i]) {
                        actualArgs[i] = ClassUtil.getComponentType(args[i]);
                    }
                }
            }
            return exec(bean, getMethod(bean.getClass(), methodName, actualArgs), args);
        } catch (Exception e) {
            log.error("[{}]对象执行{}方法异常：{}", bean.getClass().getSimpleName(), methodName, e.getMessage());
            throw new ServerException(e.getMessage());
        }
    }

    public static <T> Object exec(Object bean, Method method, Object... args) throws RuntimeException {
        try {
            if (null != args) {
                ReflectionUtils.makeAccessible(method);
                return method.invoke(bean, args);
            } else {
                ReflectionUtils.makeAccessible(method);
                return method.invoke(bean);
            }
        } catch (Exception e) {
            log.error("[{}]对象执行{}方法异常：{}", bean.getClass().getSimpleName(), method.getName(), e.getMessage());
            throw new ServerException(e.getMessage());
        }
    }
}
